home *** CD-ROM | disk | FTP | other *** search
/ AGA Toolkit '97 / The AGA Toolkit '97.iso / miscellaneous / science / maths / calc / source / addop.c next >
Encoding:
C/C++ Source or Header  |  1996-09-07  |  9.7 KB  |  439 lines

  1. /*
  2.  * Copyright (c) 1994 David I. Bell
  3.  * Permission is granted to use, distribute, or modify this source,
  4.  * provided that this copyright notice remains intact.
  5.  *
  6.  * Add opcodes to a function being compiled.
  7.  */
  8.  
  9. #include "calc.h"
  10. #include "opcodes.h"
  11. #include "string.h"
  12. #include "func.h"
  13. #include "token.h"
  14. #include "label.h"
  15. #include "symbol.h"
  16.  
  17.  
  18. #define    FUNCALLOCSIZE    20    /* reallocate size for functions */
  19. #define    OPCODEALLOCSIZE    100    /* reallocate size for opcodes in functions */
  20.  
  21.  
  22. static long maxopcodes;        /* number of opcodes available */
  23. static long newindex;        /* index of new function */
  24. static long oldop;        /* previous opcode */
  25. static long debugline;        /* line number of latest debug opcode */
  26. static long funccount;        /* number of functions */
  27. static long funcavail;        /* available number of functions */
  28. static FUNC *functemplate;    /* function definition template */
  29. static FUNC **functions;    /* table of functions */
  30. static STRINGHEAD funcnames;    /* function names */
  31. static int codeflag;
  32.  
  33.  
  34. /*
  35.  * Initialize the table of user defined functions.
  36.  */
  37. void
  38. initfunctions()
  39. {
  40.     initstr(&funcnames);
  41.     maxopcodes = OPCODEALLOCSIZE;
  42.     functemplate = (FUNC *) malloc(funcsize(maxopcodes));
  43.     if (functemplate == NULL)
  44.         math_error("Cannot allocate function template");
  45.     functions = (FUNC **) malloc(sizeof(FUNC *) * FUNCALLOCSIZE);
  46.     if (functions == NULL)
  47.         math_error("Cannot allocate function table");
  48.     funccount = 0;
  49.     funcavail = FUNCALLOCSIZE;
  50. }
  51.  
  52.  
  53. /*
  54.  * Show the list of user defined functions.
  55.  */
  56. void
  57. showfunctions()
  58. {
  59.     FUNC **fpp;        /* pointer into function table */
  60.     FUNC *fp;        /* current function */
  61.  
  62.     if (funccount == 0) {
  63.         printf("No user functions defined.\n");
  64.         return;
  65.     }
  66.     printf("Name Arguments\n");
  67.     printf("---- ---------\n");
  68.     for (fpp = &functions[funccount - 1]; fpp >= functions; fpp--) {
  69.         fp = *fpp;
  70.         if (fp == NULL)
  71.             continue;
  72.         printf("%-12s %-2d\n", fp->f_name, fp->f_paramcount);
  73.     }
  74.     printf("\n");
  75. }
  76.  
  77.  
  78. /*
  79.  * Initialize a function for definition.
  80.  * Newflag is TRUE if we should allocate a new function structure,
  81.  * instead of the usual overwriting of the template function structure.
  82.  * The new structure is returned in the global curfunc variable.
  83.  */
  84. void
  85. beginfunc(name, newflag)
  86.     char *name;            /* name of function */
  87.     BOOL newflag;            /* TRUE if need new structure */
  88. {
  89.     register FUNC *fp;        /* current function */
  90.  
  91.     newindex = adduserfunc(name);
  92.     maxopcodes = OPCODEALLOCSIZE;
  93.     fp = functemplate;
  94.     if (newflag) {
  95.         fp = (FUNC *) malloc(funcsize(maxopcodes));
  96.         if (fp == NULL)
  97.             math_error("Cannot allocate temporary function");
  98.     }
  99.     fp->f_next = NULL;
  100.     fp->f_localcount = 0;
  101.     fp->f_opcodecount = 0;
  102.     fp->f_savedvalue.v_type = V_NULL;
  103.     fp->f_name = namestr(&funcnames, newindex);
  104.     curfunc = fp;
  105.     initlocals();
  106.     initlabels();
  107.     oldop = OP_NOP;
  108.     debugline = 0;
  109.     errorcount = 0;
  110. }
  111.  
  112.  
  113. /*
  114.  * Commit the just defined function for use.
  115.  * This replaces any existing definition for the function.
  116.  * This should only be called for normal user-defined functions.
  117.  */
  118. void
  119. endfunc()
  120. {
  121.     register FUNC *fp;        /* function just finished */
  122.     long size;            /* size of just created function */
  123.  
  124.     checklabels();
  125.     if (errorcount) {
  126.         printf("\"%s\": %ld error%s\n", curfunc->f_name, errorcount,
  127.             ((errorcount == 1) ? "" : "s"));
  128.         return;
  129.     }
  130.     size = funcsize(curfunc->f_opcodecount);
  131.     fp = (FUNC *) malloc(size);
  132.     if (fp == NULL)
  133.         math_error("Cannot commit function");
  134.     memcpy((char *) fp, (char *) curfunc, size);
  135.     if (curfunc != functemplate)
  136.         free(curfunc);
  137.     if (codeflag) {
  138.         for (size = 0; size < fp->f_opcodecount; ) {
  139.             printf("%ld: ", (long)size);
  140.             size += dumpop(&fp->f_opcodes[size]);
  141.         }
  142.     }
  143.     if (functions[newindex])
  144.         free(functions[newindex]);
  145.     functions[newindex] = fp;
  146.     objuncache();
  147.     if (inputisterminal())
  148.         printf("\"%s\" defined\n", fp->f_name);
  149. }
  150.  
  151.  
  152. /*
  153.  * Find the user function with the specified name, and return its index.
  154.  * If the function does not exist, its name is added to the function table
  155.  * and an error will be generated when it is called if it is still undefined.
  156.  */
  157. long
  158. adduserfunc(name)
  159.     char *name;        /* name of function */
  160. {
  161.     long index;        /* index of function */
  162.  
  163.     index = findstr(&funcnames, name);
  164.     if (index >= 0)
  165.         return index;
  166.     if (funccount >= funcavail) {
  167.         functions = (FUNC **) realloc(functions,
  168.             sizeof(FUNC *) * (funcavail + FUNCALLOCSIZE));
  169.         if (functions == NULL)
  170.             math_error("Failed to reallocate function table");
  171.         funcavail += FUNCALLOCSIZE;
  172.     }
  173.     if (addstr(&funcnames, name) == NULL)
  174.         math_error("Cannot save function name");
  175.     index = funccount++;
  176.     functions[index] = NULL;
  177.     return index;
  178. }
  179.  
  180.  
  181. /*
  182.  * Clear any optimization that may be done for the next opcode.
  183.  * This is used when defining a label.
  184.  */
  185. void
  186. clearopt()
  187. {
  188.     oldop = OP_NOP;
  189.     debugline = 0;
  190. }
  191.  
  192.  
  193. /*
  194.  * Find a function structure given its index.
  195.  */
  196. FUNC *
  197. findfunc(index)
  198.     long index;
  199. {
  200.     if ((unsigned long) index >= funccount)
  201.         math_error("Undefined function");
  202.     return functions[index];
  203. }
  204.  
  205.  
  206. /*
  207.  * Return the name of a function given its index.
  208.  */
  209. char *
  210. namefunc(index)
  211.     long index;
  212. {
  213.     return namestr(&funcnames, index);
  214. }
  215.  
  216.  
  217. /*
  218.  * Let a matrix indexing operation know that it will be treated as a write
  219.  * reference instead of just as a read reference.
  220.  */
  221. void
  222. writeindexop()
  223. {
  224.     if (oldop == OP_INDEXADDR)
  225.         curfunc->f_opcodes[curfunc->f_opcodecount - 1] = TRUE;
  226. }
  227.  
  228.  
  229. /*
  230.  * Add an opcode to the current function being compiled.
  231.  * Note: This can change the curfunc global variable when the
  232.  * function needs expanding.
  233.  */
  234. void
  235. addop(op)
  236.     long op;
  237. {
  238.     register FUNC *fp;        /* current function */
  239.     NUMBER *q;
  240.  
  241.     fp = curfunc;
  242.     if ((fp->f_opcodecount + 5) >= maxopcodes) {
  243.         maxopcodes += OPCODEALLOCSIZE;
  244.         fp = (FUNC *) malloc(funcsize(maxopcodes));
  245.         if (fp == NULL)
  246.             math_error("cannot malloc function");
  247.         memcpy((char *) fp, (char *) curfunc,
  248.             funcsize(curfunc->f_opcodecount));
  249.         if (curfunc != functemplate)
  250.             free(curfunc);
  251.         curfunc = fp;
  252.     }
  253.     /*
  254.      * Check the current opcode against the previous opcode and try to
  255.      * slightly optimize the code depending on the various combinations.
  256.      */
  257.     if (op == OP_GETVALUE) {
  258.         switch (oldop) {
  259.  
  260.         case OP_NUMBER: case OP_ZERO: case OP_ONE: case OP_IMAGINARY:
  261.         case OP_GETEPSILON: case OP_SETEPSILON: case OP_STRING:
  262.         case OP_UNDEF: case OP_GETCONFIG: case OP_SETCONFIG:
  263.             return;
  264.         case OP_DUPLICATE:
  265.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_DUPVALUE;
  266.             oldop = OP_DUPVALUE;
  267.             return;
  268.         case OP_FIADDR:
  269.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_FIVALUE;
  270.             oldop = OP_FIVALUE;
  271.             return;
  272.         case OP_GLOBALADDR:
  273.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_GLOBALVALUE;
  274.             oldop = OP_GLOBALVALUE;
  275.             return;
  276.         case OP_LOCALADDR:
  277.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_LOCALVALUE;
  278.             oldop = OP_LOCALVALUE;
  279.             return;
  280.         case OP_PARAMADDR:
  281.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_PARAMVALUE;
  282.             oldop = OP_PARAMVALUE;
  283.             return;
  284.         case OP_ELEMADDR:
  285.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_ELEMVALUE;
  286.             oldop = OP_ELEMVALUE;
  287.             return;
  288.         }
  289.     }
  290.     if ((op == OP_NEGATE) && (oldop == OP_NUMBER)) {
  291.         q = constvalue(fp->f_opcodes[fp->f_opcodecount - 1]);
  292.         fp->f_opcodes[fp->f_opcodecount - 1] = addqconstant(qneg(q));
  293.         oldop = OP_NUMBER;
  294.         return;
  295.     }
  296.     if ((op == OP_POWER) && (oldop == OP_NUMBER)) {
  297.         if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 2L) == 0) {
  298.             fp->f_opcodecount--;
  299.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
  300.             oldop = OP_SQUARE;
  301.             return;
  302.         }
  303.         if (qcmpi(constvalue(fp->f_opcodes[fp->f_opcodecount - 1]), 4L) == 0) {
  304.             fp->f_opcodes[fp->f_opcodecount - 2] = OP_SQUARE;
  305.             fp->f_opcodes[fp->f_opcodecount - 1] = OP_SQUARE;
  306.             oldop = OP_SQUARE;
  307.             return;
  308.         }
  309.     }
  310.     if ((op == OP_POP) && (oldop == OP_ASSIGN)) {    /* optimize */
  311.         fp->f_opcodes[fp->f_opcodecount - 1] = OP_ASSIGNPOP;
  312.         oldop = OP_ASSIGNPOP;
  313.         return;
  314.     }
  315.     /*
  316.      * No optimization possible, so store the opcode.
  317.      */
  318.     fp->f_opcodes[fp->f_opcodecount] = op;
  319.     fp->f_opcodecount++;
  320.     oldop = op;
  321. }
  322.  
  323.  
  324. /*
  325.  * Add an opcode and and one integer argument to the current function
  326.  * being compiled.
  327.  */
  328. void
  329. addopone(op, arg)
  330.     long op;
  331.     long arg;
  332. {
  333.     NUMBER *q;
  334.  
  335.     switch (op) {
  336.     case OP_NUMBER:
  337.         q = constvalue(arg);
  338.         if (q == NULL)
  339.             break;
  340.         if (qiszero(q)) {
  341.             addop(OP_ZERO);
  342.             return;
  343.         }
  344.         if (qisone(q)) {
  345.             addop(OP_ONE);
  346.             return;
  347.         }
  348.         break;
  349.  
  350.     case OP_DEBUG:
  351.         if ((traceflags & TRACE_NODEBUG) || (arg == debugline))
  352.             return;
  353.         debugline = arg;
  354.         if (oldop == OP_DEBUG) {
  355.             curfunc->f_opcodes[curfunc->f_opcodecount - 1] = arg;
  356.             return;
  357.         }
  358.         break;
  359.     }
  360.     addop(op);
  361.     curfunc->f_opcodes[curfunc->f_opcodecount] = arg;
  362.     curfunc->f_opcodecount++;
  363. }
  364.  
  365.  
  366. /*
  367.  * Add an opcode and and two integer arguments to the current function
  368.  * being compiled.
  369.  */
  370. void
  371. addoptwo(op, arg1, arg2)
  372.     long op;
  373.     long arg1;
  374.     long arg2;
  375. {
  376.     addop(op);
  377.     curfunc->f_opcodes[curfunc->f_opcodecount++] = arg1;
  378.     curfunc->f_opcodes[curfunc->f_opcodecount++] = arg2;
  379. }
  380.  
  381.  
  382. /*
  383.  * Add an opcode and a character pointer to the function being compiled.
  384.  */
  385. void
  386. addopptr(op, ptr)
  387.     long op;
  388.     char *ptr;
  389. {
  390.     char **ptraddr;
  391.  
  392.     addop(op);
  393.     ptraddr = (char **) &curfunc->f_opcodes[curfunc->f_opcodecount];
  394.     *ptraddr = ptr;
  395.     curfunc->f_opcodecount += PTR_SIZE;
  396. }
  397.  
  398.  
  399. /*
  400.  * Add an opcode and an index and an argument count for a function call.
  401.  */
  402. void
  403. addopfunction(op, index, count)
  404.     int count;
  405.     long op;
  406.     long index;
  407. {
  408.     long newop;
  409.  
  410.     if ((op == OP_CALL) && ((newop = builtinopcode(index)) != OP_NOP)) {
  411.         if ((newop == OP_SETCONFIG) && (count == 1))
  412.             newop = OP_GETCONFIG;
  413.         if ((newop == OP_SETEPSILON) && (count == 0))
  414.             newop = OP_GETEPSILON;
  415.         if ((newop == OP_ABS) && (count == 1))
  416.             addop(OP_GETEPSILON);
  417.         addop(newop);
  418.         return;
  419.     }
  420.     addop(op);
  421.     curfunc->f_opcodes[curfunc->f_opcodecount++] = index;
  422.     curfunc->f_opcodes[curfunc->f_opcodecount++] = count;
  423. }
  424.  
  425.  
  426. /*
  427.  * Add a jump-type opcode and a label to the function being compiled.
  428.  */
  429. void
  430. addoplabel(op, label)
  431.     long op;
  432.     LABEL *label;        /* label to be added */
  433. {
  434.     addop(op);
  435.     uselabel(label);
  436. }
  437.  
  438. /* END CODE */
  439.